export interface DragVerificationOptions {
  container: HTMLElement | null;
  width?: number;
  height?: number;
  text?: string;
  onSuccess?: () => void;
  onFail?: () => void;
}

export interface DragVerificationState {
  isVerified: boolean;
  sliderLeft: number;
  isDragging: boolean;
}

/**
 * DragVerification - A lightweight drag verification plugin
 */
export default class DragVerification {
  private options: DragVerificationOptions;
  private isDragging: boolean;
  private sliderLeft: number;
  private isVerified: boolean;
  private textElement: HTMLElement | null;
  private progressElement: HTMLElement | null;
  private sliderElement: HTMLElement | null;
  private startX: number;
  private startLeft: number;

  /**
   * Create a new DragVerification instance
   * @param options - Configuration options
   */
  constructor(options: DragVerificationOptions) {
    this.options = {
      width: 300,
      height: 40,
      text: '请向右滑动验证',
      onSuccess: () => {},
      onFail: () => {},
      ...options
    };

    this.isDragging = false;
    this.sliderLeft = 0;
    this.isVerified = false;
    this.textElement = null;
    this.progressElement = null;
    this.sliderElement = null;
    this.startX = 0;
    this.startLeft = 0;
    
    // 检查容器是否已有实例
    if (this.options.container && (this.options.container as any)._dragVerification) {
      // 如果已有实例，恢复其状态
      const existingInstance = (this.options.container as any)._dragVerification;
      this.isVerified = existingInstance.isVerified;
      this.sliderLeft = existingInstance.sliderLeft;
      
      // 如果已经验证成功，直接应用成功状态
      if (this.isVerified) {
        this.createElements();
        this.bindEvents();
        this.applyVerifiedState();
        return;
      }
    }
    
    this.init();
    
    // 保存实例到容器元素，防止重新渲染时丢失
    if (this.options.container) {
      (this.options.container as any)._dragVerification = this;
    }
  }

  /**
   * Initialize the verification
   */
  private init(): void {
    if (!this.options.container) {
      throw new Error('Container element is required');
    }

    this.createElements();
    this.bindEvents();
  }

  /**
   * Create the necessary DOM elements
   */
  private createElements(): void {
    if (!this.options.container) return;

    // 创建容器样式
    this.options.container.style.position = 'relative';
    this.options.container.style.width = `${this.options.width}px`;
    this.options.container.style.height = `${this.options.height}px`;
    this.options.container.style.backgroundColor = '#f5f5f5';
    this.options.container.style.border = '1px solid #e8e8e8';
    this.options.container.style.borderRadius = '4px';
    this.options.container.style.overflow = 'hidden';

    // 创建文本元素
    this.textElement = document.createElement('div');
    this.textElement.style.position = 'absolute';
    this.textElement.style.width = '100%';
    this.textElement.style.height = '100%';
    this.textElement.style.display = 'flex';
    this.textElement.style.alignItems = 'center';
    this.textElement.style.justifyContent = 'center';
    this.textElement.style.color = '#999';
    this.textElement.style.userSelect = 'none';
    this.textElement.textContent = this.options.text || '';

    // 创建进度条元素
    this.progressElement = document.createElement('div');
    this.progressElement.style.position = 'absolute';
    this.progressElement.style.left = '0';
    this.progressElement.style.top = '0';
    this.progressElement.style.width = '0';
    this.progressElement.style.height = '100%';
    this.progressElement.style.backgroundColor = 'rgba(24, 144, 255, 0.2)';

    // 创建滑块元素
    this.sliderElement = document.createElement('div');
    this.sliderElement.style.position = 'absolute';
    this.sliderElement.style.left = '0';
    this.sliderElement.style.top = '0';
    this.sliderElement.style.width = '40px';
    this.sliderElement.style.height = '100%';
    this.sliderElement.style.backgroundColor = '#1890ff';
    this.sliderElement.style.cursor = 'pointer';
    this.sliderElement.style.display = 'flex';
    this.sliderElement.style.alignItems = 'center';
    this.sliderElement.style.justifyContent = 'center';
    this.sliderElement.style.color = 'white';
    this.sliderElement.style.userSelect = 'none';
    this.sliderElement.style.transition = 'background-color 0.3s';
    this.sliderElement.textContent = '→';

    // 添加悬停效果
    this.sliderElement.addEventListener('mouseover', () => {
      if (!this.isVerified && this.sliderElement) {
        this.sliderElement.style.backgroundColor = '#40a9ff';
      }
    });

    this.sliderElement.addEventListener('mouseout', () => {
      if (!this.isVerified && this.sliderElement) {
        this.sliderElement.style.backgroundColor = '#1890ff';
      }
    });

    // 将元素添加到容器中
    this.options.container.appendChild(this.textElement);
    this.options.container.appendChild(this.progressElement);
    this.options.container.appendChild(this.sliderElement);
  }

  /**
   * Bind event listeners
   */
  private bindEvents(): void {
    if (!this.sliderElement) return;

    this.handleMouseDown = this.handleMouseDown.bind(this);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.handleMouseUp = this.handleMouseUp.bind(this);

    this.sliderElement.addEventListener('mousedown', this.handleMouseDown);
  }

  /**
   * Handle mouse down event
   * @param e - Mouse event
   */
  private handleMouseDown(e: MouseEvent): void {
    if (this.isVerified || !this.sliderElement) return;
    
    this.isDragging = true;
    this.startX = e.clientX;
    this.startLeft = this.sliderLeft;
    
    document.addEventListener('mousemove', this.handleMouseMove);
    document.addEventListener('mouseup', this.handleMouseUp);
  }

  /**
   * Handle mouse move event
   * @param e - Mouse event
   */
  private handleMouseMove(e: MouseEvent): void {
    if (!this.isDragging || !this.sliderElement || !this.progressElement) return;

    const containerRect = this.options.container?.getBoundingClientRect();
    if (!containerRect) return;
    
    // 计算鼠标移动的距离
    const moveX = e.clientX - this.startX;
    // 基于起始位置和移动距离计算新位置
    const newLeft = this.startLeft + moveX;

    // 限制滑块在有效范围内
    if (newLeft >= 0 && newLeft <= (this.options.width || 300) - 40) {
      this.sliderLeft = newLeft;
      this.sliderElement.style.left = `${this.sliderLeft}px`;
      this.progressElement.style.width = `${this.sliderLeft + 20}px`;
    } else if (newLeft < 0) {
      // 限制在左边界
      this.sliderLeft = 0;
      this.sliderElement.style.left = '0';
      this.progressElement.style.width = '20px';
    } else if (newLeft > (this.options.width || 300) - 40) {
      // 限制在右边界
      this.sliderLeft = (this.options.width || 300) - 40;
      this.sliderElement.style.left = `${this.sliderLeft}px`;
      this.progressElement.style.width = `${this.sliderLeft + 20}px`;
    }
  }

  /**
   * Handle mouse up event
   */
  private handleMouseUp(): void {
    if (!this.isDragging || !this.sliderElement || !this.progressElement) return;
    
    // 先移除事件监听器，防止重复触发
    document.removeEventListener('mousemove', this.handleMouseMove);
    document.removeEventListener('mouseup', this.handleMouseUp);
    
    this.isDragging = false;
    const threshold = (this.options.width || 300) - 40;

    if (this.sliderLeft >= threshold - 5) {
      // 验证成功，保持在终点位置
      this.sliderLeft = threshold;
      this.sliderElement.style.left = `${this.sliderLeft}px`;
      this.progressElement.style.width = `${this.sliderLeft + 20}px`;
      this.isVerified = true;
      this.sliderElement.textContent = '✓';
      this.sliderElement.style.cursor = 'default';
      
      // 直接调用回调，不使用 setTimeout
      if (this.options.onSuccess) {
        this.options.onSuccess();
      }
    } else {
      // 验证失败，回到起点
      // 添加重置动画
      this.progressElement.style.transition = 'width 0.3s';
      this.sliderElement.style.transition = 'left 0.3s';
      
      this.sliderLeft = 0;
      this.sliderElement.style.left = `${this.sliderLeft}px`;
      this.progressElement.style.width = '0';
      
      // 动画结束后移除过渡效果
      setTimeout(() => {
        if (this.progressElement && this.sliderElement) {
          this.progressElement.style.transition = '';
          this.sliderElement.style.transition = 'background-color 0.3s';
        }
        
        if (this.options.onFail) {
          this.options.onFail();
        }
      }, 300);
    }
  }

  /**
   * Apply verified state
   */
  private applyVerifiedState(): void {
    if (!this.sliderElement || !this.progressElement) return;
    
    const threshold = (this.options.width || 300) - 40;
    this.sliderLeft = threshold;
    this.sliderElement.style.left = `${this.sliderLeft}px`;
    this.progressElement.style.width = `${this.sliderLeft + 20}px`;
    this.isVerified = true;
    this.sliderElement.textContent = '✓';
    this.sliderElement.style.cursor = 'default';
  }

  /**
   * Reset the verification
   */
  public reset(): void {
    if (!this.sliderElement || !this.progressElement) return;
    
    this.isVerified = false;
    this.sliderLeft = 0;
    this.sliderElement.style.left = `${this.sliderLeft}px`;
    this.progressElement.style.width = '0';
    this.sliderElement.textContent = '→';
    this.sliderElement.style.cursor = 'pointer';
  }

  /**
   * Get the current state of the verification
   * @returns The current state
   */
  public getState(): DragVerificationState {
    return {
      isVerified: this.isVerified,
      sliderLeft: this.sliderLeft,
      isDragging: this.isDragging
    };
  }

  /**
   * Destroy the verification instance
   */
  public destroy(): void {
    if (this.sliderElement) {
      this.sliderElement.removeEventListener('mousedown', this.handleMouseDown);
    }
    document.removeEventListener('mousemove', this.handleMouseMove);
    document.removeEventListener('mouseup', this.handleMouseUp);
    
    // 清除容器上的实例引用
    if (this.options.container && (this.options.container as any)._dragVerification === this) {
      (this.options.container as any)._dragVerification = null;
    }
    
    if (this.options.container) {
      this.options.container.innerHTML = '';
    }
  }
} 